/**
 *
 */
package org.gbif.crawler.console.action;

import org.gbif.crawler.service.api.model.CrawlableResource.PRIORITY;
import org.gbif.crawler.service.api.service.CrawlableResourceService;

import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author tim
 */
public class JobAction extends ActionSupport {
  private static final Logger LOG = LoggerFactory.getLogger(JobAction.class);
  private static final long serialVersionUID = -6589735207872069978L;
  private static final ObjectMapper MAPPER = new ObjectMapper();
  private static final String SUCCESS_JSON = "json";
  private static final String SUCCESS_204 = "204";
  private String jobId;

  // for simple AJAX responses
  private InputStream inputStream;

  @Inject @Named("jmxServer")
  private String jmxUrl;

  @Inject
  private CrawlableResourceService resourceService;

  /**
   * Convenience method
   */
  protected String asJSON(Object o) {
    try {
      inputStream = IOUtils.toInputStream(MAPPER.writeValueAsString(o));
    } catch (IOException e) {
      LOG.warn("Couldn't serialize objects into JSON", e);
      e.printStackTrace();
    }
    return SUCCESS_JSON;
  }

  /**
   * Lists the resources that are marked as critically urgent to crawl.
   * @return A JSON ready stream listing the resources.
   */
  public String criticalPriority() {
    return asJSON(resourceService.list(PRIORITY.CRITICAL));
  }

  public InputStream getInputStream() {
    return inputStream;
  }

  /**
   * Lists the resources that are marked as high priority to crawl.
   * @return A JSON ready stream listing the high priority resources.
   */
  public String highPriority() {
    return asJSON(resourceService.list(PRIORITY.HIGH));
  }

  /**
   * Lists the resources that have crawled less records than advertised.
   * @return A JSON ready stream listing the resources.
   */
  public String missingRecords() {
    return asJSON(resourceService.listUnderCrawled());
  }

  /**
   * Lists the resources that have not been seen online for a month or more.
   * @return A JSON ready stream listing the resources.
   */
  public String offline() {
    GregorianCalendar cal = new GregorianCalendar();
    cal.roll(Calendar.MONTH, -3);
    return asJSON(resourceService.listNotSeenOnlineSince(cal.getTime()));
  }

  /**
   * Lists the resources that have more records that advertised.
   * @return A JSON ready stream listing the resources.
   */
  public String overCrawled() {
    return asJSON(resourceService.listOverCrawled());
  }

  /**
   * Lists the resources that have finished crawling in the last month.
   * @return A JSON ready stream listing the resources.
   */
  public String recentlyFinished() {
    GregorianCalendar cal = new GregorianCalendar();
    cal.roll(Calendar.MONTH, -1);
    return asJSON(resourceService.listFinishedSince(cal.getTime()));
  }

  /**
   * Lists the resources that are indicating reporting errors.
   * @return A JSON ready stream listing the resources.
   */
  public String reportingErrors() {
    return asJSON(resourceService.reportingErrors());
  }

  /**
   * Lists the resources that have the started flag set.
   * @return A JSON ready stream listing the resources.
   */
  public String running() {
    return asJSON(resourceService.listStarted());
  }

//  public String running() {
//    JMXConnector jmxc = null;
//    try {
//      JMXServiceURL url = new JMXServiceURL(jmxUrl);
//      jmxc = JMXConnectorFactory.connect(url, null);
//      MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
//      Set<ObjectName> running = mbsc.queryNames(null, new ObjectName(CrawlJobStatus.DOMAIN + ":*"));
//      List<Job> results = new ArrayList<Job>();
//      for (ObjectName o : running) {
//        // use the copy constructor, as Jackson does not like the proxy
//        CrawlJobStatus job = new CrawlJobStatus(JMX.newMBeanProxy(mbsc, o, CrawlJobStatusMBean.class, true));
//        results.add(new Job("1", o.getCanonicalName(),job));
//      }
//      return asJSON(results);
//    } catch (Exception e) {
//      LOG.error(e.getMessage(), e);
//    } finally {
//      IOUtils.closeQuietly(jmxc);
//    }
//    return ActionSupport.ERROR;
//  }

  public void setJobId(String jobId) {
    this.jobId = jobId;
  }

  public String terminate() {
    JMXConnector jmxc = null;
    try {
      JMXServiceURL url = new JMXServiceURL(jmxUrl);
      jmxc = JMXConnectorFactory.connect(url, null);
      MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
      // for some reason the proxy version appears not to work
      mbsc.invoke(new ObjectName(jobId), "terminate", null, null);
    } catch (Exception e) {
      e.printStackTrace();
      LOG.error(e.getMessage(), e);
    } finally {
      IOUtils.closeQuietly(jmxc);
    }
    return SUCCESS_204;
  }
}
